import { shallowReactive, reactive, h, ref, Ref } from 'vue';
import { IPSDETreeNode } from '@ibiz/dynamic-model-api';
import { AppMobTreeProps, IParam, IMobTreeCtrlController, MobTreeCtrlController, ModelTool, Util } from 'ibz-core';
import { GenerateComponent } from '../component-base';
import { MDCtrlComponentBase } from './md-ctrl-component-base';

/**
 * 移动端树部件
 *
 * @export
 * @class AppMobTree
 * @extends MDCtrlComponentBase
 */
export class AppMobTree extends MDCtrlComponentBase<AppMobTreeProps> {
  /**
   * @description 树视图部件控制器
   * @protected
   * @type {IMobTreeCtrlController}
   * @memberof AppMobTree
   */
  protected c!: IMobTreeCtrlController;

  /**
   * @description 长按定时器
   * @type {Ref<any>}
   * @memberof AppMobTree
   */
  public touchTimer: Ref<any> = ref(0);

  /**
   * @description 当前激活节点
   * @type {*}
   * @memberof AppMobTree
   */
  public activeNode: any = reactive({});

  /**
   * @description 是否打开上下文菜单
   * @type {*}
   * @memberof AppMobTree
   */
  public isShowContextMenu: boolean = true;

  /**
   * @description 初始化响应式
   * @memberof AppMobTree
   */
  setup() {
    this.c = shallowReactive<MobTreeCtrlController>(this.getCtrlControllerByType('TREE') as MobTreeCtrlController);
    super.setup();
  }

  /**
   * @description 根据类型加载节点模型
   * @param {string} type
   * @return {*}  {(IPSDETreeNode | undefined)}
   * @memberof AppMobTree
   */
  public getNodeByType(type: string): IPSDETreeNode | undefined {
    const treeNodes = this.c.controlInstance.getPSDETreeNodes() || [];
    return treeNodes.find((node: IPSDETreeNode) => node.nodeType.toLowerCase() == type.toLowerCase());
  }

  /**
   * @description 清除定时器
   * @memberof AppMobTree
   */
  public clearTimer() {
    clearInterval(this.touchTimer.value);
    this.touchTimer.value = 0;
  }

  /**
   * @description 长按开始
   * @param {*} item 节点数据
   * @param {*} event 事件源
   * @memberof AppMobTree
   */
  public onTouchStart(item: any, event: MouseEvent) {
    this.touchTimer.value = setInterval(() => {
      this.activeNode.value = {
        key: item.id,
        type: item.id.split(';')[0],
        mouseEvent: event,
        navDatas: item.curData,
        show: true,
      };
      this.isShowContextMenu = true;
      this.clearTimer();
    }, 500);
  }

  /**
   * @description 处理树节点点击事件
   * @param {IParam} item 树节点数据
   * @param {IPSDETreeNode} node 树节点模型
   * @param {*} event 源事件对象
   * @memberof AppMobTree
   */
  public handleTreeNodeClick(item: IParam, node: IPSDETreeNode, event: any) {
    const hasChildren = node.hasPSDETreeNodeRSs?.();
    if (hasChildren) {
      this.loadChildNodeData(item, event);
    } else {
      if (Object.is('SELECT', this.c.ctrlShowMode) && this.c.isMultiple) {
        this.treeNodeChecked(item, event);
      } else {
        this.treeNodeSelect(item, event);
      }
    }
  }

  /**
   * @description 单选选中数据变化
   * @param {IParam} item 节点数据
   * @param {MouseEvent} event 事件源
   * @memberof AppMobTree
   */
  public treeNodeSelect(item: IParam, event: MouseEvent) {
    if (this.c.handleTreeNodeSelect && this.c.handleTreeNodeSelect instanceof Function) {
      this.c.handleTreeNodeSelect(item, event);
    }
  }

  /**
   * @description 多项选择选中数据
   * @param {*} event 数据源
   * @memberof AppMobTree
   */
  public treeNodeChecked(item: IParam, event: any) {
    event.stopPropagation();
    if (this.c.handleTreeNodeChecked && this.c.handleTreeNodeChecked instanceof Function) {
      this.c.handleTreeNodeChecked(item, event);
    }
  }

  /**
   * @description 树节点点击
   * @param {IParam} item 节点数据
   * @param {MouseEvent} event 事件源
   * @memberof AppMobTree
   */
  public loadChildNodeData(item: IParam, event: MouseEvent) {
    if (this.c.loadChildNodeData && this.c.loadChildNodeData instanceof Function) {
      this.c.loadChildNodeData(item, event);
    }
  }

  /**
   * @description 渲染单选树
   * @return {*}
   * @memberof AppMobTree
   */
  public renderSingleTree() {
    const value = this.c.selections[0]?.id;
    return (
      <div class='tree-node--container is-single'>
        <ion-radio-group class='tree-node--radio-group' value={value}>
          {this.c.items.map((item: IParam) => {
            const node = this.getNodeByType(item.nodeType);
            return this.renderTreeNode(node as IPSDETreeNode, item);
          })}
        </ion-radio-group>
      </div>
    );
  }

  /**
   * @description 渲染多选树
   * @return {*}
   * @memberof AppMobTree
   */
  public renderMultipleTree() {
    return (
      <div class='tree-node--container is-multiple'>
        {this.c.items.map((item: IParam) => {
          const node = this.getNodeByType(item.nodeType);
          return this.renderTreeNode(node as IPSDETreeNode, item);
        })}
      </div>
    );
  }

  /**
   * @description 渲染默认树
   * @return {*}
   * @memberof AppMobTree
   */
  public renderDefaultTree() {
    return (
      <div class='tree-node--container'>
        {this.c.items.map((item: IParam) => {
          const node = this.getNodeByType(item.nodeType);
          return this.renderTreeNode(node as IPSDETreeNode, item);
        })}
      </div>
    );
  }

  /**
   * @description 渲染树主体内容
   * @return {*}
   * @memberof AppMobTree
   */
  public renderTreeMainContent() {
    if (Object.is('SELECT', this.c.ctrlShowMode)) {
      if (this.c.isMultiple) {
        return this.renderMultipleTree();
      } else {
        return this.renderSingleTree();
      }
    } else {
      return this.renderDefaultTree();
    }
  }

  /**
   * @description
   * @param {IParam} node
   * @return {*}
   * @memberof AppMobTree
   */
  /**
   * @description 渲染树节点标题
   * @param {IParam} item 树节点数据
   * @param {boolean} [hasChildren] 是否有子节点
   * @return {*}
   * @memberof AppMobTree
   */
  public renderNodeLabel(item: IParam, hasChildren?: boolean) {
    // 绘制图标
    let iconElement: any = null;
    if (item.iconCustomCode) {
      const icon = '';
      if (item.iconScriptCode.indexOf('return') !== -1) {
        item.iconScriptCode = item.iconScriptCode.replace(new RegExp('return', 'g'), `icon =`);
      }
      eval(item.iconScriptCode);
      iconElement = h('span', { innerHTML: icon });
    } else if (item.icon) {
      iconElement = <app-icon icon={item.icon}></app-icon>;
    } else if (item.iconSrc) {
      iconElement = <app-icon iconSrc={item.iconSrc}></app-icon>;
    } else if (this.c.controlInstance.outputIconDefault) {
      iconElement = <app-icon name='home'></app-icon>;
    }
    // 绘制显示文本
    let textElement: any = null;
    if (item.textCustomCode) {
      const text = '';
      if (item.textScriptCode.indexOf('return') !== -1) {
        item.textScriptCode = item.textScriptCode.replace(new RegExp('return', 'g'), `text =`);
      }
      eval(item.textScriptCode);
      textElement = h('span', { innerHTML: text });
    } else {
      textElement = <span>{item.text}</span>;
    }
    // 树节点计数器
    const nodeCountBadge = {
      count: this.c.getCounterData(item),
      showZero: item.counterMode !== 1,
      offset: [10, 10],
    };
    return (
      <ion-label title={item.tooltip ? item.tooltip : null} class='tree-node--label' v-badge={nodeCountBadge}>
        {iconElement ? <span class='tree-node--label-icon'>{iconElement}</span> : null}
        <span class='tree-node--label-content'>
          {item.isUseLangRes ? this.$tl(item.lanResTag, textElement) : textElement}
        </span>
        {hasChildren ? (
          <app-icon
            class='tree-node--select-icon'
            name={item.expanded ? 'chevron-down-outline' : 'chevron-forward-outline'}
          />
        ) : null}
      </ion-label>
    );
  }

  /**
   * @description 渲染树节点
   * @param {IPSDETreeNode} node
   * @param {IParam} item
   * @return {*}
   * @memberof AppMobTree
   */
  public renderTreeNode(node: IPSDETreeNode, item: IParam) {
    const hasChildren = node?.hasPSDETreeNodeRSs?.();
    return (
      <div class={['tree-node', item.cssName]}>
        <ion-item
          class='tree-node--content'
          onTouchstart={(event: any) => {
            this.onTouchStart(node, event);
          }}
          onTouchend={(event: any) => {
            this.clearTimer();
          }}
          onTouchmove={(event: any) => {
            this.clearTimer();
          }}
          onClick={(event: any) => {
            this.handleTreeNodeClick(item, node, event);
          }}
        >
          {Object.is('SELECT', this.c.ctrlShowMode) && !hasChildren ? (
            this.c.isMultiple ? (
              <ion-checkbox slot='start' value={item.selected}></ion-checkbox>
            ) : (
              <ion-radio slot='start' value={item.id}></ion-radio>
            )
          ) : null}
          {this.renderNodeLabel(item, hasChildren ? hasChildren : false)}
        </ion-item>
        {hasChildren && item.expanded && item.children && item.children.length > 0 ? (
          <div class='tree-node--children'>
            {item.children.map((_item: IParam) => {
              const _node = this.getNodeByType(_item.nodeType);
              return this.renderTreeNode(_node as IPSDETreeNode, _item);
            })}
          </div>
        ) : null}
      </div>
    );
  }

  /**
   * @description 渲染上下文菜单
   * @return {*}
   * @memberof AppMobTree
   */
  public renderContextMenu() {
    const type = this.activeNode.value?.type || '';
    const mouseEvent = this.activeNode.value?.mouseEvent;
    const navDatas = this.activeNode.value?.navDatas;
    if (type && mouseEvent) {
      const treeNode = (this.c.controlInstance.getPSDETreeNodes() || []).find((node: IPSDETreeNode) => {
        return node.nodeType.toLowerCase() == type.toLowerCase();
      });
      const contextMenu = ModelTool.findPSControlByName(
        treeNode?.getPSDEContextMenu?.()?.name as string,
        this.c.controlInstance.getPSControls(),
      );
      if (treeNode && contextMenu && this.isShowContextMenu) {
        this.isShowContextMenu = false;
        const otherParams = {
          key: Util.createUUID(),
          navDatas: [navDatas],
          mouseEvent: mouseEvent,
          contextMenuActionModel: {},
        };
        return this.computeTargetCtrlData(contextMenu, otherParams);
      }
    }
  }

  /**
   * @description 渲染树部件
   * @return {*}
   * @memberof AppMobTree
   */
  render() {
    if (!this.controlIsLoaded.value) {
      return;
    }
    const { width, height } = this.c.controlInstance;
    const controlstyle = {
      width: width ? `${width}px` : '100%',
      height: height ? `${height}px` : '100%',
    };
    return (
      <div class={{ ...this.classNames }} style={controlstyle}>
        {this.renderPullDownRefresh()}
        {this.renderContextMenu()}
        {this.renderTreeMainContent()}
      </div>
    );
  }
}

export const AppMobTreeComponent = GenerateComponent(AppMobTree, Object.keys(new AppMobTreeProps()));
